package br.ufmg.vod.wbr.graphs;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import br.ufmg.vod.wbr.algorithims.cluster.ClusteringCoefficient;
import br.ufmg.vod.wbr.algorithims.components.WeaklyConnectedComponentBFS;

public class GoogleAPGraphLoader implements GraphLoader<FastGraph> {

	private final File graph;
	private final File maps;
	private final double threshold;

	public GoogleAPGraphLoader(File graph, File maps, double threshold) {
		this.graph = graph;
		this.maps = maps;
		this.threshold = threshold;
	}

	@Override
	public FastGraph loadGraph() throws Exception {
		Map<Integer, Integer> fid2id = new HashMap<Integer, Integer>();
		Map<Integer, Integer> id2len = new HashMap<Integer, Integer>();
		BufferedReader reader = new BufferedReader(new FileReader(maps));
		int numVertex = loadIds(fid2id, id2len, reader);
		reader.close();
		
		System.out.println("Loaded ids");
		System.out.println(numVertex);
		
		int[][] g = new int[numVertex][];
		for (int i = 0; i < numVertex; i++) {
			Integer len = id2len.remove(i);
			if (len == null) {
				g[i] = new int[0];
			} else {
				g[i] = new int[len];
			}
		}
		
		reader = new BufferedReader(new FileReader(graph));
		loadGraph(fid2id, id2len, reader, g);
		reader.close();
		return new FastGraph(g);
	}

	private void loadGraph(Map<Integer, Integer> fid2id, Map<Integer, Integer> id2len, BufferedReader reader, int[][] g) throws IOException {
		int x = 0;
		String line;
		while ((line = reader.readLine()) != null) {
			String[] split = line.split(",");
			
			int fid = Integer.parseInt(split[0]);
			int id = fid2id.get(fid);
			
			for (int i = 0; i < g[id].length; i++) {
				int neighbor = Integer.parseInt(split[1]);
				double weight = Double.parseDouble(split[2]);
				
				if (weight >= threshold) {
					int integer = fid2id.get(neighbor);
					g[id][i] = integer;
				}
				
				line = reader.readLine();
				if (line == null) {
					break;
				}
				split = line.split(",");
			}
			if (++x % 1000 == 0) {
				System.out.println(x);
			}
		}
	}

	private int loadIds(Map<Integer, Integer> fid2id, Map<Integer, Integer> id2len, BufferedReader reader) throws IOException {
		int numVertex = 0;
		String line;
		while ((line = reader.readLine()) != null) {
			String[] split = line.split("\\s+");
			int id = Integer.parseInt(split[0]);
			int len = Integer.parseInt(split[1]);
			
			fid2id.put((int)id, numVertex);
			id2len.put(numVertex, (int)len);
			numVertex++;
		}
		return numVertex;
	}
	
	public static void main(String[] args) throws Exception {		
		String edges = args[0];
		String ids = args[1];
		double threshold = Integer.parseInt(args[2]);
		File outDir= new File(args[3]);
		
		File f = new File(edges);
		File f2 = new File(ids);
		double t = threshold;
		
		if (!outDir.isDirectory()) {
			System.err.println("Given parameter is not a directory. (" + outDir + ")");
			System.exit(1);
		}
		
		if (outDir.listFiles() != null && outDir.listFiles().length != 0) {
			System.err.println("Directory is not empty, may corrupt data in directory. Aborting. (" + outDir + ")");
			System.exit(1);
		}
		
		FastGraph loadGraph = new GoogleAPGraphLoader(f, f2, t).loadGraph();
		WeaklyConnectedComponentBFS wcc = new WeaklyConnectedComponentBFS(loadGraph);
		wcc.run();
		
		summarize(outDir, loadGraph, wcc);
	}

	private static void summarize(File outDir, FastGraph loadGraph,
			WeaklyConnectedComponentBFS wcc) throws IOException {
		ArrayList<Integer> distribution = new ArrayList<Integer>();
		for (int[] component : wcc.getComponents()) {
			distribution.add(component.length);
		}
		Map<Integer, Double> pdf = StatsPrinter.pdf(distribution);
		Map<Integer, Double> cdf = StatsPrinter.cdf(pdf);
		StatsPrinter.printStats(new File(outDir.getAbsolutePath() + File.separator + "wcc.stats"), distribution);
		StatsPrinter.printMap("", new File(outDir.getAbsolutePath() + File.separator + "wcc.pdf"), pdf);
		StatsPrinter.printMap("", new File(outDir.getAbsolutePath() + File.separator + "wcc.cdf"), cdf);
		
		int[][] allEdges = loadGraph.getAllEdges();
		distribution.clear();
		for (int i = 0; i < allEdges.length; i++) {
			distribution.add(allEdges[i].length);
		}
		pdf = StatsPrinter.pdf(distribution);
		cdf = StatsPrinter.cdf(pdf);
		StatsPrinter.printStats(new File(outDir.getAbsolutePath() + File.separator + "edge.stats"), distribution);
		StatsPrinter.printMap("", new File(outDir.getAbsolutePath() + File.separator + "edge.pdf"), pdf);
		StatsPrinter.printMap("", new File(outDir.getAbsolutePath() + File.separator + "edge.cdf"), cdf);
		
		ClusteringCoefficient cc = new ClusteringCoefficient(loadGraph);
		cc.run();
		distribution.clear();
		for (int i = 0; i < allEdges.length; i++) {
			distribution.add((int)(cc.res[i] * 1000));
		}
		pdf = StatsPrinter.pdf(distribution);
		cdf = StatsPrinter.cdf(pdf);
		StatsPrinter.printStats(new File(outDir.getAbsolutePath() + File.separator + "cc.stats"), distribution);
		StatsPrinter.printMap("", new File(outDir.getAbsolutePath() + File.separator + "cc.pdf"), pdf);
		StatsPrinter.printMap("", new File(outDir.getAbsolutePath() + File.separator + "cc.cdf"), cdf);

		PrintWriter w = new PrintWriter(new FileWriter(new File(outDir.getAbsolutePath() + File.separator + "graph.stats")));
		w.println("#vertex " + loadGraph.getNumVertex());
		w.println("#edges " + loadGraph.getNumEdges());
		w.close();
	}
}